package re_0905.question_ioc.annotation;


import re_0905.question_ioc.MoterAutowired;
import re_0905.question_ioc.MoterService;

import java.io.File;
import java.lang.reflect.Field;
import java.nio.file.NoSuchFileException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 自定义ioc容器，未解决循环依赖，未实现缓存。
 */
public class MoterBeanFactory implements BeanFactory, BeanRegister, BeanDI {

    private String path;
    private ConcurrentHashMap<String, Object> beans = null;
    private final String rootPath = this.getClass().getResource("/").getPath();
    private final String DEFAULT_PATH = rootPath + this.getClass().getPackage().getName();
    List<Class<?>> classes = null;

    public MoterBeanFactory() {
        path = DEFAULT_PATH;

    }

    public MoterBeanFactory(String path) {
        this.path = path;
    }

    public void init() throws Exception {
        classes = new ArrayList<>();
        //扫包 把当前包所有类放入classes
        saoBao(path.replace(".", "/"));
        //从classes里面取出所有类，判断是否被注解，是否需要加入bean容器
        register();
        //从容器里面取出所有类，判断是否有成员变脸被MoterAutoWired修饰，注入到bean的实例。
        inject();
    }

    @Override
    public Object getBean(String beanId) throws Exception {
        Objects.requireNonNull(beanId, "不能为空或为null\t" + beanId);
        if (!beans.containsKey(beanId))
            throw new Exception("没有这个bean");
        return beans.get(beanId);

    }

    @Override
    public void inject() throws IllegalAccessException {
        Set<Map.Entry<String, Object>> entries = beans.entrySet();
        for (Map.Entry<String, Object> entry : entries) {
            isFieldAnnotated(entry.getValue());
        }
    }

    @Override
    public void register() throws InstantiationException, IllegalAccessException {
        beans = new ConcurrentHashMap<>();
        for (Class<?> aClass : classes) {
            isClassAnnotated(aClass);
        }
    }

    /**
     *
     * 判断 类的成员属性是否被注解了。
     * 如果有，就用过bean容器初始化这个变量。
     * @param o
     * @throws IllegalAccessException
     */
    public void isFieldAnnotated(Object o) throws IllegalAccessException {
        Field[] declaredFields = o.getClass().getDeclaredFields();
        for (Field declaredField : declaredFields) {
            if(declaredField.getAnnotation(MoterAutowired.class)!=null){
                declaredField.setAccessible(true);
                declaredField.set(o,beans.get(declaredField.getName()));
            }
        }
    }

    /**
     * 判断该类是否被自定义注解 注解了。
     * 如果是，加入bean容器
     * @param c
     * @throws IllegalAccessException
     * @throws InstantiationException
     */
    private void isClassAnnotated(Class<?> c) throws IllegalAccessException, InstantiationException {
        if (c.getAnnotation(MoterService.class) != null) {
            String name = c.getSimpleName();
            name = name.substring(0, 1).toLowerCase() + name.substring(1, name.length());
            beans.put(name, c.newInstance());
        }
    }

    /**
     * 扫描所有包，然后将所有类的Class对象放入classes
     * @param path
     * @throws Exception
     */
    public void saoBao(String path) throws Exception {
        File file = new File(path);
        if (!file.exists() || !file.isDirectory()) {
            throw new NoSuchFileException("不存在该包\t" + path);
        }

        File[] files = file.listFiles(File::isFile);
        for (File file1 : files) {
            //获得文件全路径
            String filePath = file1.getPath();
            if (filePath.endsWith(".class")) {
                //然后通过rootpath分割得到包路径，并且去除.class得到 类全路径
                String substring = rootPath.substring(1).replace("/","\\\\");
                filePath = filePath.split(substring)[1];
                filePath = filePath.replace("\\", ".").replace(".class","");
                //获得该类的反射 放入list -》classes
                classes.add(Class.forName(filePath));
            }
        }
    }

    public static void main(String[] args) throws Exception {
        MoterBeanFactory factory = new MoterBeanFactory();
        factory.init();//初始化
        factory.beans.entrySet().forEach(n-> System.out.println(n.getKey()+"\t"+n.getValue()));//查看所有bean
        MoterTestFather moterTestFather = (MoterTestFather) factory.getBean("moterTestFather");//获取bean
        System.out.println(moterTestFather);//查看获取的bean的地址
        moterTestFather.write();////调用bean方法。

    }
}
